package com.zengqingfa.threadpool;

import org.junit.Test;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Queue;
import java.util.concurrent.*;

/**
 * @fileName: ThreadPoolTest2
 * @author: zengqf3
 * @date: 2021-07-02 16:57
 * @description:
 */
public class ThreadPoolTest2 {

    /**
     * 创建固定大小的线程池
     * 线程抛出异常之后，后面的任务会创建新的线程来执行，线程，正常执行，则复用线程
     * 任务队列大小为Integer.MAX_VALUE，堆积的请求处理队列可能会耗费非常大的内存，甚至OOM
     * <p>
     * pool-1-thread-2:1
     * pool-1-thread-1:0
     * pool-1-thread-2:2
     * pool-1-thread-3:5
     * pool-1-thread-3:6
     * pool-1-thread-4:7
     * pool-1-thread-3:8
     * pool-1-thread-4:9
     * <p>
     * Exception in thread "pool-1-thread-1" Exception in thread "pool-1-thread-2" java.lang.RuntimeException: j=3 抛出异常
     * at com.zengqingfa.threadpool.ThreadPoolTest2.lambda$testNewFixedThreadExecutor$0(ThreadPoolTest2.java:24)
     * at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
     * at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
     * at java.lang.Thread.run(Thread.java:748)
     * java.lang.RuntimeException: j=4 抛出异常
     * at com.zengqingfa.threadpool.ThreadPoolTest2.lambda$testNewFixedThreadExecutor$0(ThreadPoolTest2.java:27)
     * at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
     * at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
     * at java.lang.Thread.run(Thread.java:748)
     */
    @Test
    public void testNewFixedThreadExecutor() {
        ExecutorService service =
                Executors.newFixedThreadPool(2);
        for (int i = 0; i < 10; i++) {
            int j = i;
            service.execute(() -> {
                if (j == 3) {
                    throw new RuntimeException("j=3 抛出异常");
                }
                if (j == 4) {
                    throw new RuntimeException("j=4 抛出异常");
                }
                System.out.println(Thread.currentThread().getName() + ":" + j);
            });
        }

    }


    /**
     * 创建单线程的线程池
     * 任务按顺序执行，如果任务执行失败，则会创建新的线程来执行任务，线程正常执行，则复用线程
     * 任务队列大小为Integer.MAX_VALUE，堆积的请求处理队列可能会耗费非常大的内存，甚至OOM
     * pool-1-thread-1:0
     * pool-1-thread-1:1
     * pool-1-thread-1:2
     * <p>
     * Exception in thread "pool-1-thread-1" pool-1-thread-3:5
     * Exception in thread "pool-1-thread-2" java.lang.RuntimeException: j=4 抛出异常
     * pool-1-thread-3:6
     * at com.zengqingfa.threadpool.ThreadPoolTest2.lambda$testNewSingleThreadExecutor$1(ThreadPoolTest2.java:70)
     * at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
     * at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
     * pool-1-thread-3:7
     * at java.lang.Thread.run(Thread.java:748)
     * java.lang.RuntimeException: j=3 抛出异常
     * at com.zengqingfa.threadpool.ThreadPoolTest2.lambda$testNewSingleThreadExecutor$1(ThreadPoolTest2.java:67)
     * at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
     * at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
     * at java.lang.Thread.run(Thread.java:748)
     * pool-1-thread-3:8
     * pool-1-thread-3:9
     */
    @Test
    public void testNewSingleThreadExecutor() {
        ExecutorService service =
                Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            int j = i;
            service.execute(() -> {
                if (j == 3) {
                    throw new RuntimeException("j=3 抛出异常");
                }
                if (j == 4) {
                    throw new RuntimeException("j=4 抛出异常");
                }
                System.out.println(Thread.currentThread().getName() + ":" + j);
            });
        }
    }

    /**
     * 创建可缓存的线程池，线程空闲时间为60s则销毁，如果线程执行完毕，可以复用，线程出现异常，则创建新的线程来执行任务
     * 可创建的线程数大小为Integer.MAX_VALUE，可以无线的新建线程，容易造成堆外内存溢出
     * pool-1-thread-1:0
     * pool-1-thread-2:1
     * pool-1-thread-3:2
     * pool-1-thread-3:6
     * pool-1-thread-6:5
     * pool-1-thread-2:7
     * pool-1-thread-1:8
     * pool-1-thread-9:9
     * Exception in thread "pool-1-thread-4" Exception in thread "pool-1-thread-5" java.lang.RuntimeException: j=4 抛出异常
     * at com.zengqingfa.threadpool.ThreadPoolTest2.lambda$testNewCachedThreadPool$2(ThreadPoolTest2.java:118)
     * at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
     * at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
     * at java.lang.Thread.run(Thread.java:748)
     * <p>
     * java.lang.RuntimeException: j=3 抛出异常
     * at com.zengqingfa.threadpool.ThreadPoolTest2.lambda$testNewCachedThreadPool$2(ThreadPoolTest2.java:115)
     * at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
     * at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
     * at java.lang.Thread.run(Thread.java:748)
     */
    @Test
    public void testNewCachedThreadPool() {
        ExecutorService service =
                Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            int j = i;
            service.execute(() -> {
                if (j == 3) {
                    throw new RuntimeException("j=3 抛出异常");
                }
                if (j == 4) {
                    throw new RuntimeException("j=4 抛出异常");
                }
                System.out.println(Thread.currentThread().getName() + ":" + j);
            });
        }
    }


    /**
     * 创建一个定长线程池，支持定时及周期性任务执行
     * 每一个被调度的任务都会由线程池中一个线程去执行，因此任务是并发执行的
     * 线程池的线程空闲时间为0，缓存队列为DelayedWorkQueue，一直存活
     * pool-1-thread-1 2021-07-02 16:36:51
     * callSchedule 0
     * pool-1-thread-1 2021-07-02 16:36:53
     * callSchedule 1
     * pool-1-thread-2 2021-07-02 16:36:55
     * callSchedule 2
     *
     * java.util.concurrent.ExecutionException: java.lang.RuntimeException: j=3 抛出异常
     */
    @Test
    public void testNewScheduledThreadPool() throws Exception {
        ScheduledExecutorService service =
                Executors.newScheduledThreadPool(2);
        for (int i = 0; i < 10; i++) {
            int j = i;
            ScheduledFuture<String> future = service.schedule(new Callable<String>() {
                @Override
                public String call()  {
                    if (j == 3) {
                        throw new RuntimeException("j=3 抛出异常");
                    }
                    if (j == 4) {
                        throw new RuntimeException("j=4 抛出异常");
                    }
                    System.out.println(Thread.currentThread().getName() + " " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                    return "callSchedule "+j;
                }
            }, 2, TimeUnit.SECONDS);
            System.out.println(future.get());
        }
    }
}
